package k8s

import (
	"context"
	"errors"
	"net"

	"gitee.com/linxing_3/sr-core/plugins/log"
	"gitee.com/mkwchecking/sr-admin/pkg/file"
	"k8s.io/client-go/kubernetes"
	"k8s.io/client-go/rest"
	"k8s.io/client-go/tools/clientcmd"
)

func New(cfg *Config) (*K8sClient, error) {
	if cfg.InCluster {
		return NewInClusterClient()
	}

	return NewOutClusterClient(cfg)
}

func NewInClusterClient() (*K8sClient, error) {
	cfg, err := rest.InClusterConfig()
	if err != nil {
		return nil, err
	}
	return NewClient(cfg)
}

func NewOutClusterClient(cfg *Config) (*K8sClient, error) {
	if cfg.SVRHost == "" {
		return nil, errors.New("k8s server host is empty, but it's required")
	}

	host := "https://" + net.JoinHostPort(cfg.SVRHost, cfg.SVRPort)

	var config *rest.Config
	var err error

	if cfg.ConfigFile != "" && file.Exists(cfg.ConfigFile) {
		config, err = clientcmd.BuildConfigFromFlags(host, cfg.ConfigFile)
	} else {
		config = &rest.Config{
			Host: host,
			TLSClientConfig: rest.TLSClientConfig{
				CertFile: cfg.CertFile,
				KeyFile:  cfg.KeyFile,
				CertData: []byte(cfg.CertData),
				KeyData:  []byte(cfg.KeyData),
			},
			BearerToken: cfg.Token,
		}
	}
	if err != nil {
		return nil, err
	}

	return NewClient(config)
}
func NewClient(cfg *rest.Config) (*K8sClient, error) {
	clientSet, err := kubernetes.NewForConfig(cfg)
	if err != nil {
		return nil, err
	}

	return (&K8sClient{clientSet: clientSet}).Watch(context.Background()), nil
}

type K8sClient struct {
	clientSet *kubernetes.Clientset

	job         *Jobs        // Job
	configMap   *ConfigMap   // ConfigMap
	daemonSet   *DaemonSet   // DaemonSet
	deployment  *Deployment  // Deployment
	namespace   *Namespace   // Namespace
	node        *Node        // Node
	pods        *Pods        // Pods
	secret      *Secret      // Secret
	service     *Service     // Service
	statefulSet *StatefulSet // StatefulSet
}

func (s *K8sClient) Watch(ctx context.Context, list ...string) *K8sClient {
	if len(list) == 0 {
		return s
	}

	if list[0] == "all" {
		if err := s.node.Watch(ctx); err != nil {
			log.Errorf("watch node failed: %s", err)
		}
	}

	return s
}

func (s *K8sClient) Job() *Jobs {
	if s.job == nil {
		s.job = NewJobs(s.clientSet)
	}
	return s.job
}
func (s *K8sClient) ConfigMap() *ConfigMap {
	if s.configMap == nil {
		s.configMap = NewConfigMap(s.clientSet)
	}
	return s.configMap
}
func (s *K8sClient) DaemonSet() *DaemonSet {
	if s.daemonSet == nil {
		s.daemonSet = NewDaemonSet(s.clientSet)
	}
	return s.daemonSet
}
func (s *K8sClient) Deployment() *Deployment {
	if s.deployment == nil {
		s.deployment = NewDeployment(s.clientSet)
	}
	return s.deployment
}
func (s *K8sClient) Namespace() *Namespace {
	if s.namespace == nil {
		s.namespace = NewNamespace(s.clientSet)
	}
	return s.namespace
}
func (s *K8sClient) Node() *Node {
	if s.node == nil {
		s.node = NewNode(s.clientSet)
	}
	return s.node
}
func (s *K8sClient) Pods() *Pods {
	if s.pods == nil {
		s.pods = NewPods(s.clientSet)
	}
	return s.pods
}
func (s *K8sClient) Secret() *Secret {
	if s.secret == nil {
		s.secret = NewSecret(s.clientSet)
	}
	return s.secret
}
func (s *K8sClient) Service() *Service {
	if s.service == nil {
		s.service = NewService(s.clientSet)
	}
	return s.service
}
func (s *K8sClient) StatefulSet() *StatefulSet {
	if s.statefulSet == nil {
		s.statefulSet = NewStatefulSet(s.clientSet)
	}
	return s.statefulSet
}
